home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Container Common / CBaseSite.cpp < prev    next >
Text File  |  1997-01-03  |  17KB  |  895 lines

  1. //
  2. //  XSITE.CPP
  3. //
  4. //  Copyright (C) Microsoft Corporation, 1996
  5. //
  6. #include "headers.h"
  7. #include <ctype.h>
  8. #include "MacMisc.h"
  9. #include "CActiveXScheduler.h"
  10.  
  11. static CCodeDownload*    CodeDownload;
  12. static void toLower(char* src);
  13. static LPOLESTR StrDup(LPCOLESTR psz);
  14.  
  15.  
  16. #pragma mark === CBaseSite::Construction & Destruction ===
  17.  
  18. /*************************** Construction/Destruction *****************/
  19.  
  20. //
  21. //  CBaseSite::CreateCBaseSite
  22. //
  23.  
  24. CXSite *CXSite::CreateSite(void)
  25. {
  26.     return new CXSite();
  27. }
  28.  
  29.  
  30. //
  31. //  CBaseSite::CBaseSite
  32. //
  33.  
  34. CXSite::CXSite(void)
  35. {
  36.     m_ClientInstance = 0L;
  37.     m_pszCodeURL = NULL;
  38.     m_BaseURL = NULL;
  39.     m_dwMinimumVersion = 0L;
  40.     m_fHaveInitialStream = false;
  41.     
  42.  
  43.  #ifdef PLUGIN_ADAPTER
  44.     m_pInitialDataStreamNotify = NULL;
  45.     m_pUnattachedList = NULL;
  46. #endif
  47.  
  48.     m_punkObject = NULL;
  49.  
  50.     mUnkOuter = nil;
  51.     mContainerP = nil;
  52.     mContainerData = NULL;
  53.     mObjSiteP = NULL;
  54.     mControlP = NULL;
  55.     mPropertyBagP = NULL;
  56.  
  57.     mContextCount = 1;
  58.     mCachedDraw = false;
  59.     mCachedContextChange = false;
  60.     mCachedActiveContextID = InvalidContextID;
  61.  
  62.     mHavePort = false;
  63.     mOldPortState.ClipRgn = NULL;
  64.     mBindHostP = NULL;
  65.     mThreadScheduler = NULL;
  66.     mDestroyed = false;
  67. }
  68.  
  69.  
  70. //
  71. //  CBaseSite::~CBaseSite
  72. //
  73.  
  74. CXSite::~CXSite(void)
  75. {
  76. #ifdef PLUGIN_ADAPTER
  77.     if (m_pInitialDataStreamNotify != NULL)
  78.         delete m_pInitialDataStreamNotify;
  79. #endif
  80.      if (m_BaseURL != NULL)
  81.         CoTaskMemFree(m_BaseURL);
  82.     if (m_pszCodeURL != NULL)
  83. //        CoTaskMemFree(m_pszCodeURL);
  84.         DisposePtr(m_pszCodeURL);
  85.  
  86.     if ( mContainerP )
  87.         mContainerP->Release(); 
  88.     if ( mBindHostP )
  89.         delete mBindHostP; 
  90. }
  91.  
  92.  
  93. #pragma mark === CBaseSite::Non Interface functions ===
  94.  
  95. //
  96. //  CBaseSite::AddParam
  97. //
  98.  
  99. STDMETHODIMP
  100. CXSite::AddParam (Char8* inName, Char8* inValue)
  101. {
  102.     LPOLESTR    LowerCaseName = StrDup(inName);
  103.     
  104.      if ( LowerCaseName )
  105.         toLower(LowerCaseName);
  106.     else
  107.         return E_OUTOFMEMORY;    
  108.  
  109.     if ( !mPropertyBagP )
  110.     {
  111.            if ((mPropertyBagP = new CPropertyBag()) == NULL)
  112.             return E_OUTOFMEMORY;    
  113.     }
  114.  
  115.     if (strcmp(LowerCaseName, "codebase") == 0)
  116.     {
  117.         if ((m_pszCodeURL = (LPOLESTR)StrDup((Char8*)inValue)) != NULL)
  118.         {
  119.             GetVersionFromURL(m_pszCodeURL, &m_dwMinimumVersion);
  120.         }
  121.     } 
  122.     else if (strcmp(LowerCaseName, "classid") == 0)
  123.     {
  124.         toLower(inValue);
  125.         if( strncmp(inValue, "clsid:", 6) == 0)
  126.             CLSIDFromString((Char8*)inValue + 6, &m_clsid);
  127.     }
  128.     else
  129.     {
  130.         mPropertyBagP->AddParam(LowerCaseName, inValue );
  131.     }
  132.     DisposePtr(LowerCaseName);
  133.  
  134.     return S_OK;
  135. }
  136.  
  137.  
  138. //
  139. //  CBaseSite::FindControl
  140. //
  141. #define    kCLSIDConst            "CLSID\\"
  142.  
  143. STDMETHODIMP
  144. CXSite::FindControl(void)
  145. {
  146.     HKEY        hKey;
  147.     char*        CLSIDString;
  148.     char        Key[256];
  149.     
  150.     StringFromCLSID(m_clsid, &CLSIDString);
  151.     Key[0] = '\0';
  152.     strcat(Key, kCLSIDConst);
  153.     strcat(Key, CLSIDString);
  154. #undef CoTaskMemFree        // StringFromCLSID used CoTaskMemAlloc so don't us debug version
  155.      CoTaskMemFree(CLSIDString);
  156. #ifdef CHECKMEMORYLEAKS
  157. #define CoTaskMemFree       DebugCoTaskMemFree
  158. #endif
  159.     if (RegOpenKey(HKEY_CLASSES_ROOT, Key, &hKey) == S_OK)
  160.     {
  161.         RegCloseKey(hKey);
  162.         return S_OK;
  163.     }
  164.     else if (m_pszCodeURL == NULL ||
  165.             GetFileTypeFromExtension(m_pszCodeURL) == FILEXTN_UNKNOWN)
  166.             return E_UNEXPECTED;
  167.  
  168.     return S_OK;
  169. }
  170.  
  171. //
  172. //  CBaseSite::CreateControl
  173. //
  174.  
  175. STDMETHODIMP
  176. CXSite::CreateControl(Boolean8 inDoDownload)
  177. {
  178.     ErrorCode     Result;
  179.     LPUNKNOWN     punkPersist;
  180.  
  181.     if (m_punkObject != NULL || mDestroyed)
  182.         return E_ABORT;
  183.  
  184.     if(!mBindHostP)
  185.         mBindHostP = new CBindHost(this);
  186.     //  Attempt to create the object.  The latest OLE Controls guidelines only
  187.     //  require the object to support IUnknown.
  188.     if (FAILED(Result = CoCreateInstance(m_clsid, NULL, CLSCTX_INPROC_SERVER,
  189.         IID_IUnknown, (LPVOID *) &m_punkObject)))
  190.     {
  191.         // if we need to download, and the client says it is okay, do it
  192.         // otherwise, just pass the error back so the client can deal with it
  193.         if ( Result == REGDB_E_CLASSNOTREG || Result == CO_E_DLLNOTFOUND)
  194.         {
  195.             if (m_pszCodeURL == NULL ||
  196.                 GetFileTypeFromExtension(m_pszCodeURL) == FILEXTN_UNKNOWN)
  197.                 return E_UNEXPECTED;
  198.             if(!inDoDownload )
  199.                 return Result;
  200.  
  201.             //  Create the download object for this container if not already available.
  202.             if (CodeDownload == NULL) 
  203.             {
  204.                 if ((CodeDownload = new CCodeDownload()) == NULL)
  205.                     return E_FAIL;
  206.             }
  207.             AddRef();        //    accout for this pointer
  208.             CodeDownload->QueueDownload(this);
  209.             return E_PENDING;
  210.         }
  211.         return E_FAIL;
  212.     }
  213.  
  214.     // See if this is an in-proc object
  215.     if (SUCCEEDED(m_punkObject->QueryInterface(IID_IObjectWithSite, (LPVOID *) &mObjSiteP))) 
  216.     {
  217.         mObjSiteP->SetSite((IUnknown*) (void*)  this);
  218.         if (FAILED(m_punkObject->QueryInterface(IID_IControl, (LPVOID *) &mControlP)))
  219.             mControlP = nil; 
  220.     } 
  221.     else
  222.         mObjSiteP = NULL;
  223.        
  224.     if ( !mControlP )
  225.         goto CreateFailure;
  226.     
  227.     if (SUCCEEDED(m_punkObject->QueryInterface(IID_IPersistPropertyBag,(LPVOID *) &punkPersist)))
  228.     {
  229.         Result = ((LPPERSISTPROPERTYBAG) punkPersist)->Load( mPropertyBagP, NULL);
  230.         punkPersist->Release();
  231.     
  232.     }
  233. #ifdef PLUGIN_ADAPTER
  234.     else  if (m_pInitialDataStreamNotify != NULL &&
  235.                 SUCCEEDED(m_punkObject->QueryInterface(IID_IPersistStream,
  236.                 (LPVOID *) &punkPersist)))
  237.     {
  238.         m_pInitialDataStreamNotify->m_SeekPosition = sizeof(CLSID);
  239.         Result = ((LPPERSISTSTREAM) punkPersist)->Load((LPSTREAM)
  240.             m_pInitialDataStreamNotify);
  241.         punkPersist->Release();
  242.     }
  243.     delete m_pInitialDataStreamNotify;
  244.     m_pInitialDataStreamNotify = NULL;
  245. #endif
  246.  
  247.     if (FAILED(Result))
  248.         goto CreateFailure;
  249.  
  250.     if ( mCachedContextChange )
  251.     {
  252.         UInt32            ContextID;
  253.         Int32            Index = 0;
  254.         
  255.         while ( GetContextID(++Index, &ContextID))
  256.         {
  257.             mControlP->OnContextChange(ContextID, AddContext);
  258.             if (ContextID == mCachedActiveContextID)
  259.                 mControlP->OnContextChange(ContextID, ActivateContext);
  260.         }
  261.  
  262.         mCachedContextChange = false;
  263.     }
  264.  
  265.     if ( mCachedDraw )
  266.     {
  267.         DrawControl();
  268.         mCachedDraw = false;
  269.     }
  270.  
  271.  
  272.     return S_OK;
  273.  
  274.     //  Cleanup after anything that we've already done and unload the object.
  275. CreateFailure:
  276.     DestroyControl();
  277.     return E_FAIL;
  278.  
  279. }
  280.  
  281.  
  282. //
  283. //  CBaseSite::DestroyControl
  284. //
  285.  
  286. STDMETHODIMP
  287. CXSite::DestroyControl(void)
  288. {
  289.     mDestroyed = true;
  290.  
  291.     if ( mPropertyBagP )
  292.         ReleaseAndNull(mPropertyBagP);
  293.     
  294.     if(mBindHostP != NULL)
  295.         mBindHostP->AbortBindings();
  296.         
  297.     if (mControlP != NULL) 
  298.         ReleaseAndNull(mControlP);
  299.  
  300.     if (mObjSiteP != NULL) 
  301.     {
  302.         mObjSiteP->SetSite(NULL);
  303.         ReleaseAndNull(mObjSiteP);
  304.     }
  305.  
  306.     SafeReleaseAndNull(m_punkObject);
  307.     CoFreeUnusedLibraries();    // unload the com object if not used
  308.     
  309.     return S_OK;
  310. }
  311.  
  312.  
  313. //
  314. //  CBaseSite::SetContainerData
  315. //
  316. //  Sets the container data for the site
  317. //
  318.  
  319. STDMETHODIMP
  320. CXSite::SetContainerData(IUnknown* inUnkOuter, void  *inContainerData)
  321. {
  322.     mUnkOuter = inUnkOuter;
  323.     if (mContainerP)
  324.         mContainerP->Release();
  325.     mUnkOuter->QueryInterface(IID_IContainer, &mContainerP);
  326.     mContainerData = inContainerData;
  327.        return S_OK;
  328. }
  329.  
  330.  
  331. //
  332. //  CBaseSite::GetContainerData
  333. //
  334. //  Returns the container
  335. //
  336.  
  337. STDMETHODIMP
  338. CXSite::GetContainerData(void** outContainerData)
  339. {
  340.     *outContainerData = mContainerData;
  341.     return S_OK;
  342. }
  343.  
  344. //
  345. //  CBaseSite::SetBaseURL
  346. //
  347. //  Sets the base URL for this site
  348. //
  349.  
  350. STDMETHODIMP
  351. CXSite::SetBaseURL(Char8* inURL)
  352. {
  353.     if ( m_BaseURL )
  354.     {
  355.         CoTaskMemFree(m_BaseURL);
  356.         m_BaseURL = nil;
  357.     }
  358.         
  359.     m_BaseURL = OleStrdup(inURL);
  360.    
  361.     return S_OK;
  362. }
  363.  
  364. //
  365. //    CBaseSite::DrawControl
  366. //
  367.  
  368. void CXSite::DrawControl(void)
  369. {
  370.     if ( mControlP )
  371.     {
  372.         DrawContext        Context = {BeginPortType};
  373.         UInt32            ContextID;
  374.         long            Index = 1;
  375.         
  376.         while( GetContextID(Index++, &ContextID) )
  377.         {
  378.             AcquireContext(ContextID, &Context);
  379.             mControlP->Draw(&Context);
  380.             ReleaseContext(&Context);
  381.         }
  382.     }
  383.     else
  384.         mCachedDraw = true;
  385. }
  386.  
  387.  
  388. //
  389. //  CBaseSite::SavePortState
  390. //
  391.  
  392. void CXSite::SavePortState(PlatformPort* Port)
  393. {
  394.     // Save off the current port
  395.     ::GetPort(&mSavePort);
  396.     
  397.     // Set the current port to the one requested
  398.     ::SetPort(Port);
  399.     
  400.     // Save off the port rect and clip
  401.     mOldPortState.PortRect = Port->portRect;
  402.     mOldPortState.ClipRgn = NewRgn();
  403.     ::GetClip(mOldPortState.ClipRgn);
  404.     
  405.     // Save off the pen state
  406.     ::GetPenState(&mOldPortState.PenState);
  407.     mOldPortState.TextFont = Port->txFont;
  408.     mOldPortState.TextMode = Port->txMode;
  409.     mOldPortState.TextSize = Port->txSize;
  410.     mOldPortState.TextFace = Port->txFace;
  411.     ::GetForeColor(&mOldPortState.ForeColor);
  412.     ::GetBackColor(&mOldPortState.BackColor);
  413. }
  414.  
  415.  
  416. //
  417. //  CBaseSite::RestorePortState
  418. //
  419.  
  420. void CXSite::RestorePortState(void)
  421. {
  422.     //  Undo everything we did to "thePort" in AcquirePort.
  423.     ::SetOrigin(mOldPortState.PortRect.left, mOldPortState.PortRect.top);
  424.     if (mOldPortState.ClipRgn)
  425.     {
  426.         ::SetClip(mOldPortState.ClipRgn);
  427.         ::DisposeRgn(mOldPortState.ClipRgn);
  428.         mOldPortState.ClipRgn = NULL;
  429.     }
  430.  
  431.     // Restore the current state of things
  432.     ::SetPenState(&mOldPortState.PenState);
  433.     ::TextFont(mOldPortState.TextFont);
  434.     ::TextFace(mOldPortState.TextFace);
  435.     ::TextMode(mOldPortState.TextMode);
  436.     ::TextSize(mOldPortState.TextSize);
  437.     ::RGBForeColor(&mOldPortState.ForeColor);
  438.     ::RGBBackColor(&mOldPortState.BackColor);
  439.  
  440.     // Set back to original port
  441.     ::SetPort(mSavePort);
  442.  
  443. }
  444.  
  445.  
  446. //
  447. //  CBaseSite::GetContextID
  448. //
  449. //    all containers MUST OVERRIDE this
  450.  
  451. Boolean8
  452. CXSite::GetContextID(Int32 inContextIndex, UInt32* outContextID)
  453. {
  454. #pragma unused (inContextIndex, outContextID)
  455.     return false;
  456. }
  457.  
  458.  
  459. #pragma mark === CBaseSite::IUnknown Interfaces ===
  460.  
  461. /************************* IUnknown Interfaces *************************/
  462. //
  463. //  CBaseSite::IUnknown::QueryInterface
  464. //
  465. //  Returns a pointer to the specified interface on a component to which a
  466. //  client currently holds an interface pointer.
  467. //
  468. STDMETHODIMP
  469. CXSite::QueryInterface(REFIID inRefID, void** outObj)
  470. {
  471.     ErrorCode Result = CBaseCOM::QueryInterface( inRefID, outObj);
  472.     
  473.     if ( Result == E_NOINTERFACE )
  474.     {
  475.         void* pv = nil;
  476.  
  477.         if ( inRefID == IID_IControl )
  478.             pv = (void*)(IControl*) this;
  479.         else if ( inRefID == IID_IContainerSite )
  480.             pv = (void*)(IContainerSite*) this;
  481.         else if (inRefID == IID_IServiceProvider)
  482.             pv = (void*)(LPSERVICEPROVIDER) this;
  483.         else if (inRefID == IID_IBindHost)
  484.             pv = (void*)(LPBINDHOST) mBindHostP;
  485.         else if (inRefID == IID_IThreadScheduler)
  486.             pv = (void*)(IThreadScheduler*) this;
  487.             
  488.         *outObj = pv;
  489.     
  490.         if ( pv )
  491.         {
  492.             ((IUnknown*) pv)->AddRef();
  493.             Result = S_OK;
  494.         }
  495.     }
  496.     
  497.     return Result;
  498.  
  499. }
  500.  
  501.  
  502.  
  503. #pragma mark === CBaseSite::IContainerSite Interfaces ===
  504.  
  505. //
  506. //  CBaseSite::IContainerSite::GetContainer
  507. //
  508. //  Returns the container
  509. //
  510.  
  511. STDMETHODIMP
  512. CXSite::GetContainer(IContainer** outContainer)
  513. {
  514.     // Caller's responsibility to AddRef the container interface
  515.     *outContainer = mContainerP;
  516.     return S_OK;
  517. }
  518.  
  519.  
  520. //
  521. //  CBaseSite::IContainerSite::RequestFocus
  522. //
  523. //  attempt to manage focus
  524. //
  525.  
  526. STDMETHODIMP
  527. CXSite::RequestFocus ( Boolean8 /* inAcquire */, FocusSet /* inFocus */)
  528. {
  529.     return E_NOTIMPL;
  530. }
  531.  
  532.  
  533. //
  534. //  CBaseSite::RequestSizeChange
  535. //
  536. //  how to change the controls size
  537. //
  538.  
  539. STDMETHODIMP
  540. CXSite::RequestSizeChange ( Point* /* ioSize */)
  541. {
  542.     return E_NOTIMPL;
  543. }
  544.  
  545. //
  546. //  CBaseSite::OnChange
  547. //
  548. //  Notification that something of interest changed in the control
  549. //
  550.  
  551. STDMETHODIMP
  552. CXSite::OnChange (ChangeType inChangeType)
  553. {
  554.     switch (inChangeType)
  555.     {
  556.         case UsedAreaChange:
  557.             {
  558.                 DrawContext        Context = {BeginPortType};
  559.                 UInt32            ContextID;
  560.                 long            Index = 1;
  561.                 
  562.                 while( GetContextID(Index++, &ContextID) )
  563.                 {
  564.                     AcquireContext(ContextID, &Context);
  565.                     ::EraseRect(&Context.Location);
  566.                     ReleaseContext(&Context);
  567.                 }
  568.             }
  569.             break;
  570.         case ViewChange:
  571.         case DataChange:
  572.         default:
  573.             break;
  574.     }
  575.  
  576.     return S_OK;    // we don't care here
  577. }
  578.  
  579. //
  580. //  CBaseSite::IContainerSite::AcquireContext
  581. //
  582.  
  583. STDMETHODIMP
  584. CXSite::AcquireContext(Uint32 /*inContextID*/, DrawContext* /*outContext*/)
  585. {    
  586.     return  E_FAIL;
  587. }
  588.  
  589.  
  590. //
  591. //  CBaseSite::IContainerSite::ReleaseContext
  592. //
  593.  
  594. STDMETHODIMP
  595. CXSite::ReleaseContext(DrawContext* inContext)
  596. {
  597. #pragma unused (inContext)
  598.  
  599.     if (!mHavePort) 
  600.     {
  601.         //  Unbalanced GetDC/ReleaseDC calls.  Return an error.
  602.         return  E_FAIL;
  603.     }
  604.  
  605.     RestorePortState();
  606.  
  607.     mHavePort = FALSE;
  608.  
  609.     return S_OK;
  610. }
  611.  
  612.  
  613. //
  614. //  CBaseSite::IContainerSite::SetIdleTime
  615. //
  616.  
  617. STDMETHODIMP
  618. CXSite::SetIdleTime(Int32 inWaitTicks, Uint32 inRefCon)
  619. {
  620.     CActiveXScheduler*    Scheduler = CActiveXScheduler::GetActiveXScheduler(true);
  621.     ErrorCode            Result = E_FAIL;
  622.  
  623.     if (Scheduler)
  624.     {
  625.         if (inWaitTicks == RemoveAllIdlers)
  626.             Result = Scheduler->RemoveControl(this);
  627.         else if (inWaitTicks == RemoveIdler)
  628.             Result = Scheduler->RemoveControlByRefCon(this, inRefCon);
  629.         else
  630.         {
  631.             Result = Scheduler->ScheduleControl(inWaitTicks == IdleAfterAllEvents, inWaitTicks, this, inRefCon);
  632.         }
  633.     }
  634.  
  635.     return Result;
  636. }
  637.  
  638.  
  639.  
  640. #pragma mark === CBaseSite::IControl Interfaces ===
  641.  
  642. //
  643. //  CBaseSite::IControl::Draw
  644. //
  645. //  Calls the embedded object and tells it to paint itself.
  646. //
  647.  
  648. STDMETHODIMP
  649. CXSite::Draw(DrawContext* inContext)
  650. {
  651.     if ( mControlP )
  652.         mControlP->Draw(inContext);
  653.     else
  654.         mCachedDraw = true;
  655.     
  656.     return S_OK;
  657. }
  658.  
  659.  
  660. //
  661. //  CBaseSite::IControl::OnContextChange
  662. //
  663. //  Adds a context to the control
  664. //
  665.  
  666. STDMETHODIMP
  667. CXSite::OnContextChange(UInt32 inContextID, ContextCommand inCommand)
  668. {
  669.     if ( mControlP )
  670.         return mControlP->OnContextChange(inContextID, inCommand);
  671.     else
  672.     {
  673.         mCachedContextChange = true;
  674.         if (inCommand == ActivateContext)
  675.             mCachedActiveContextID = inContextID;
  676.         else if (inCommand == DeactivateContext)
  677.             mCachedActiveContextID = InvalidContextID;
  678.            return S_OK;
  679.        }
  680. }
  681.  
  682.  
  683. //
  684. //  CBaseSite::IControl::GetID
  685. //
  686. //  Returns the ID of the control
  687. //
  688.  
  689. STDMETHODIMP
  690. CXSite::GetID(Int32 inBufferSize, Char8* outID)
  691. {
  692.     if ( mControlP )
  693.         return mControlP->GetID(inBufferSize, outID);
  694.     else
  695.     {
  696.         outID[0] = 0;    // return null string    
  697.         return E_FAIL;
  698.     }
  699. }
  700.  
  701. //
  702. //  CBaseSite::IControl::GetUsedArea
  703. //
  704. //  Returns the used area of the control
  705. //
  706.  
  707. STDMETHODIMP
  708. CXSite::GetUsedArea(PlatformRegion* outUsedArea)
  709. {
  710.     if ( mControlP )
  711.         return mControlP->GetUsedArea(outUsedArea);
  712.     else
  713.         return E_FAIL;
  714. }
  715.  
  716. //
  717. //  CBaseSite::IControl::SetFocus
  718. //
  719. //  Sets or removes focus from this site
  720. //
  721.  
  722. STDMETHODIMP
  723. CXSite::SetFocus(FocusCommand inCommand, FocusSet inFocus)
  724. {
  725.     ErrorCode    theResult = S_OK;
  726.  
  727.     if ( mControlP )
  728.         theResult = mControlP->SetFocus(inCommand, inFocus);
  729.     else
  730.         theResult = E_FAIL;
  731.         
  732.     return theResult;
  733. }
  734.  
  735.  
  736. //
  737. //  CBaseSite::IControl::DoMouse
  738. //
  739.  
  740. STDMETHODIMP
  741. CXSite::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
  742. {
  743.     ErrorCode    theResult = S_OK;
  744.     
  745.     if ( mControlP )
  746.         theResult = mControlP->DoMouse(inMouseET, inEvent);
  747.     
  748.     return theResult;
  749. }
  750.  
  751.  
  752. //
  753. //  CBaseSite::IControl::DoKey
  754. //
  755.  
  756. STDMETHODIMP
  757. CXSite::DoKey(KeyEventType inKeyET, Char8 inChar, PlatformEvent* inEvent)
  758. {
  759.     ErrorCode    theResult = S_OK;
  760.     
  761.     if ( mControlP )
  762.         theResult = mControlP->DoKey(inKeyET, inChar, inEvent);
  763.     
  764.     return theResult;
  765. }
  766.  
  767.  
  768. //
  769. //  CBaseSite::IControl::DoActivate
  770. //
  771.  
  772. STDMETHODIMP
  773. CXSite::DoActivate(ActivateEventType inActiveET, UInt32 inContextID, PlatformEvent* inEvent)
  774. {
  775.     ErrorCode    theResult = S_OK;
  776.     
  777.     if ( mControlP )
  778.         theResult = mControlP->DoActivate(inActiveET, inContextID, inEvent);
  779.     
  780.     return theResult;
  781. }
  782.  
  783.  
  784. //
  785. //  CBaseSite::IControl::DoSystemEvent
  786. //
  787.  
  788. STDMETHODIMP
  789. CXSite::DoSystemEvent(PlatformEvent* inEvent)
  790. {
  791.     ErrorCode    theResult = S_OK;
  792.     
  793.     if ( mControlP )
  794.         theResult = mControlP->DoSystemEvent(inEvent);
  795.     
  796.     return theResult;
  797. }
  798.  
  799.  
  800. //
  801. //  CBaseSite::IControl::OnIdle
  802. //
  803. //  pass idle events to the control
  804. //
  805.  
  806. STDMETHODIMP
  807. CXSite::DoIdle(Uint32 IdleRefCon)
  808. {
  809.     if ( mControlP )
  810.         return mControlP->DoIdle(IdleRefCon);
  811.     else
  812.         return SetIdleTime(RemoveAllIdlers, NULL);
  813. }
  814.  
  815.  
  816. #pragma mark === CBaseSite::IServiceProvider Interface ===
  817.  
  818. //
  819. //  CBaseSite::IServiceProvider::QueryService
  820. //
  821.  
  822. STDMETHODIMP
  823. CXSite::QueryService(REFGUID inRSID, REFIID inRefID, void** outObj)
  824. {
  825.     ErrorCode Result;
  826.  
  827.     if (inRSID == SID_BindHost) 
  828.     {
  829.         //  According to the "OLE Controls/COM Objects for the Internet" spec,
  830.         //  it's legal for the site to implement this service directly on the
  831.         //  site object.
  832.         Result = this->QueryInterface(inRefID, outObj);
  833.     }
  834.     else if ( inRSID == SID_IThreads )
  835.         Result = this->QueryInterface(inRefID, outObj); 
  836.     else 
  837.     {
  838.         *outObj = NULL;
  839.         Result = E_NOINTERFACE;
  840.     }
  841.  
  842.     return Result;
  843. }
  844.  
  845.  
  846. #pragma mark === CBaseSite::IThreadScheduler Interface ===
  847.  
  848. //
  849. //  CBaseSite::IThreadScheduler::GetScheduler
  850. //
  851. STDMETHODIMP
  852. CXSite::GetScheduler(ProcPtr* outScheduler)
  853. {
  854.     *outScheduler = mThreadScheduler;
  855.     
  856.     if ( mThreadScheduler )
  857.         return S_OK;
  858.     else
  859.         return S_FALSE;
  860. }
  861.  
  862.  
  863.  
  864.  
  865.  
  866. #pragma mark === Static Utility Functions ===
  867.  
  868. //
  869. //  toLower
  870. //
  871.  
  872. static void toLower(char* src)
  873. {
  874.     for(char * p = src;*p; p++){
  875.         *p = tolower(*p);
  876.     }
  877. }
  878.  
  879.  
  880. //
  881. //  StrDup
  882. //
  883.  
  884. static LPOLESTR StrDup(LPCOLESTR psz)
  885. {
  886.     LPOLESTR pszDup;
  887.  
  888.     if ((pszDup = (LPOLESTR) NewPtr(strlen((char *) psz) + 1)) != NULL)
  889.         strcpy((char *) pszDup, (const char *) psz);
  890.  
  891.     return pszDup;
  892. }
  893.  
  894.  
  895.